home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / JTextArea.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  25.1 KB  |  767 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)JTextArea.java    1.56 98/09/18
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package javax.swing;
  15.  
  16. import java.awt.*;
  17. import java.awt.event.*;
  18. import javax.swing.text.*;
  19. import javax.swing.plaf.*;
  20. import javax.accessibility.*;
  21.  
  22. import java.io.ObjectOutputStream;
  23. import java.io.ObjectInputStream;
  24. import java.io.IOException;
  25.  
  26. /**
  27.  * A TextArea is a multi-line area that displays plain text. 
  28.  * It is intended to be a lightweight component that provides source 
  29.  * compatibility with the java.awt.TextArea class where it can
  30.  * reasonably do so.  This component has capabilities not found in 
  31.  * the java.awt.TextArea class.  The superclass should be consulted for 
  32.  * additional capabilities.  Alternative multi-line text classes with
  33.  * more capabilitites are JTextPane and JEditorPane.
  34.  * <p>
  35.  * The java.awt.TextArea internally handles scrolling.  JTextArea
  36.  * is different in that it doesn't manage scrolling, but implements
  37.  * the swing Scrollable interface.  This allows it to be placed 
  38.  * inside a JScrollPane if scrolling behavior is desired, and used
  39.  * directly if scrolling is not desired.
  40.  * <p>
  41.  * The java.awt.TextArea has the ability to do line wrapping. 
  42.  * This was controlled by the horizontal scrolling policy.  Since
  43.  * scrolling is not done by JTextArea directly, backward 
  44.  * compatibility must be provided another way.  JTextArea has
  45.  * a bound property for line wrapping that controls whether or
  46.  * not it will wrap lines.
  47.  * <p>
  48.  * The java.awt.TextArea could be monitored for changes by adding
  49.  * a TextListener for TextEvent's.  In the JTextComponent based
  50.  * components, changes are broadcasted from the model via a
  51.  * DocumentEvent to DocumentListeners.  The DocumentEvent gives 
  52.  * the location of the change and the kind of change if desired.
  53.  * The code fragment might look something like:
  54.  * <pre><code>
  55.  *    DocumentListener myListener = ??;
  56.  *    JTextArea myArea = ??;
  57.  *    myArea.getDocument().addDocumentListener(myListener);
  58.  * </code></pre>
  59.  * <p>
  60.  * For the keyboard keys used by this component in the standard Look and
  61.  * Feel (L&F) renditions, see the
  62.  * <a href="doc-files/Key-Index.html#JTextArea">JTextArea</a> key assignments.
  63.  * <p>
  64.  * <strong>Warning:</strong>
  65.  * Serialized objects of this class will not be compatible with
  66.  * future Swing releases.  The current serialization support is appropriate
  67.  * for short term storage or RMI between applications running the same
  68.  * version of Swing.  A future release of Swing will provide support for
  69.  * long term persistence.
  70.  *
  71.  * @beaninfo
  72.  *   attribute: isContainer false
  73.  * @author  Timothy Prinzing
  74.  * @version 1.56 09/18/98
  75.  * @see JTextPane
  76.  * @see JEditorPane
  77.  */
  78. public class JTextArea extends JTextComponent {
  79.  
  80.     /**
  81.      * @see #getUIClassID
  82.      * @see #readObject
  83.      */
  84.     private static final String uiClassID = "TextAreaUI";
  85.  
  86.     /**
  87.      * Constructs a new TextArea.  A default model is set, the initial string
  88.      * is null, and rows/columns are set to 0.
  89.      */
  90.     public JTextArea() {
  91.         this(null, null, 0, 0);
  92.     }
  93.  
  94.     /**
  95.      * Constructs a new TextArea with the specified text displayed.
  96.      * A default model is created and rows/columns are set to 0.
  97.      *
  98.      * @param text the text to be displayed, or null
  99.      */
  100.     public JTextArea(String text) {
  101.         this(null, text, 0, 0);
  102.     }
  103.  
  104.     /**
  105.      * Constructs a new empty TextArea with the specified number of
  106.      * rows and columns.  A default model is created, and the initial
  107.      * string is null.
  108.      *
  109.      * @param rows the number of rows >= 0
  110.      * @param columns the number of columns >= 0
  111.      */
  112.     public JTextArea(int rows, int columns) {
  113.         this(null, null, rows, columns);
  114.     }
  115.  
  116.     /**
  117.      * Constructs a new TextArea with the specified text and number
  118.      * of rows and columns.  A default model is created.
  119.      *
  120.      * @param text the text to be displayed, or null
  121.      * @param rows the number of rows >= 0
  122.      * @param columns the number of columns >= 0
  123.      */
  124.     public JTextArea(String text, int rows, int columns) {
  125.         this(null, text, rows, columns);
  126.     }
  127.  
  128.     /**
  129.      * Constructs a new JTextArea with the given document model, and defaults
  130.      * for all of the other arguments (null, 0, 0).
  131.      *
  132.      * @param doc  the model to use
  133.      */
  134.     public JTextArea(Document doc) {
  135.         this(doc, null, 0, 0);
  136.     }
  137.  
  138.     /**
  139.      * Constructs a new JTextArea with the specified number of rows
  140.      * and columns, and the given model.  All of the constructors
  141.      * feed through this constructor.
  142.      *
  143.      * @param doc the model to use, or create a default one if null
  144.      * @param text the text to be displayed, null if none
  145.      * @param rows the number of rows >= 0
  146.      * @param columns the number of columns >= 0
  147.      */
  148.     public JTextArea(Document doc, String text, int rows, int columns) {
  149.         super();
  150.         this.rows = rows;
  151.         this.columns = columns;
  152.         if (doc == null) {
  153.             doc = createDefaultModel();
  154.         }
  155.         setDocument(doc);
  156.         if (text != null) {
  157.             setText(text);
  158.         }
  159.     }
  160.  
  161.     /**
  162.      * Returns the class ID for the UI.
  163.      *
  164.      * @return the ID ("TextAreaUI")
  165.      * @see JComponent#getUIClassID
  166.      * @see UIDefaults#getUI
  167.      */
  168.     public String getUIClassID() {
  169.         return uiClassID;
  170.     }
  171.  
  172.     /**
  173.      * Creates the default implementation of the model
  174.      * to be used at construction if one isn't explicitly 
  175.      * given.  A new instance of PlainDocument is returned.
  176.      *
  177.      * @return the default document model
  178.      */
  179.     protected Document createDefaultModel() {
  180.         return new PlainDocument();
  181.     }
  182.  
  183.     /**
  184.      * Sets the number of characters to expand tabs to.
  185.      * This will be multiplied by the maximum advance for
  186.      * variable width fonts.  A PropertyChange event ("TabSize") is fired
  187.      * when the tab size changes.
  188.      *
  189.      * @param size number of characters to expand to
  190.      * @see #getTabSize
  191.      * @beaninfo
  192.      *   preferred: true
  193.      *       bound: true
  194.      * description: the number of characters to expand tabs to
  195.      */
  196.     public void setTabSize(int size) {
  197.         Document doc = getDocument();
  198.         if (doc != null) {
  199.             int old = getTabSize();
  200.             doc.putProperty(PlainDocument.tabSizeAttribute, new Integer(size));
  201.             firePropertyChange("TabSize", old, size);
  202.         }
  203.     }
  204.  
  205.     /**
  206.      * Gets the number of characters used to expand tabs.  If the document is
  207.      * null or doesn't have a tab setting, return a default of 8.
  208.      *
  209.      * @return the number of characters
  210.      */
  211.     public int getTabSize() {
  212.         int size = 8;
  213.         Document doc = getDocument();
  214.         if (doc != null) {
  215.             Integer i = (Integer) doc.getProperty(PlainDocument.tabSizeAttribute);
  216.             if (i != null) {
  217.                 size = i.intValue();
  218.             }
  219.         }
  220.         return size;
  221.     }
  222.  
  223.     /**
  224.      * Sets the line-wrapping policy of the text area.  If set
  225.      * to true the lines will be wrapped if they are too long
  226.      * to fit within the allocated width.  If set to false,
  227.      * the lines will always be unwrapped.  A PropertyChange event ("LineWrap")
  228.      * is fired when the policy is changed.
  229.      *
  230.      * @param wrap indicates if lines should be wrapped.
  231.      * @see #getLineWrap
  232.      * @beaninfo
  233.      *   preferred: true
  234.      *       bound: true
  235.      * description: should lines be wrapped
  236.      */
  237.     public void setLineWrap(boolean wrap) {
  238.         boolean old = this.wrap;
  239.         this.wrap = wrap;
  240.         firePropertyChange("LineWrap", old, wrap);
  241.     }
  242.  
  243.     /**
  244.      * Gets the line-wrapping policy of the text area.  If set
  245.      * to true the lines will be wrapped if they are too long
  246.      * to fit within the allocated width.  If set to false,
  247.      * the lines will always be unwrapped.
  248.      *
  249.      * @returns if lines will be wrapped.
  250.      */
  251.     public boolean getLineWrap() {
  252.         return wrap;
  253.     }
  254.  
  255.     /**
  256.      * Set the style of wrapping used if the text area is wrapping
  257.      * lines.  If set to true the lines will be wrapped at word
  258.      * boundries (ie whitespace) if they are too long
  259.      * to fit within the allocated width.  If set to false,
  260.      * the lines will be wrapped at character boundries.
  261.      *
  262.      * @param word indicates if word boundries should be used
  263.      *   for line wrapping.
  264.      * @see #getWrapStyleWord
  265.      * @beaninfo
  266.      *   preferred: false
  267.      *       bound: true
  268.      * description: should wrapping occur at word boundries
  269.      */
  270.     public void setWrapStyleWord(boolean word) {
  271.         boolean old = this.word;
  272.         this.word = word;
  273.         firePropertyChange("WrapStyleWord", old, word);
  274.     }
  275.  
  276.     /**
  277.      * Get the style of wrapping used if the text area is wrapping
  278.      * lines.  If set to true the lines will be wrapped at word
  279.      * boundries (ie whitespace) if they are too long
  280.      * to fit within the allocated width.  If set to false,
  281.      * the lines will be wrapped at character boundries.
  282.      *
  283.      * @returns if the wrap style should be word boundries
  284.      *  instead of character boundries.
  285.      */
  286.     public boolean getWrapStyleWord() {
  287.         return word;
  288.     }
  289.  
  290.     /**
  291.      * Translates an offset into the components text to a 
  292.      * line number.
  293.      *
  294.      * @param offset the offset >= 0
  295.      * @return the line number >= 0
  296.      * @exception BadLocationException thrown if the offset is
  297.      *   less than zero or greater than the document length.
  298.      */
  299.     public int getLineOfOffset(int offset) throws BadLocationException {
  300.         Document doc = getDocument();
  301.         if (offset < 0) {
  302.             throw new BadLocationException("Can't translate offset to line", -1);
  303.         } else if (offset > doc.getLength()) {
  304.             throw new BadLocationException("Can't translate offset to line", doc.getLength()+1);
  305.         } else {
  306.             Element map = getDocument().getDefaultRootElement();
  307.             return map.getElementIndex(offset);
  308.         }
  309.     }
  310.  
  311.     /**
  312.      * Determines the number of lines contained in the area.
  313.      *
  314.      * @return the number of lines >= 0
  315.      */
  316.     public int getLineCount() {
  317.     // There is an implicit break being modeled at the end of the
  318.     // document to deal with boundry conditions at the end.  This
  319.     // is not desired in the line count, so we detect it and remove
  320.     // its effect if throwing off the count.
  321.         Element map = getDocument().getDefaultRootElement();
  322.         int n = map.getElementCount();
  323.     Element lastLine = map.getElement(n-1);
  324.     if ((lastLine.getEndOffset() - lastLine.getStartOffset()) > 1) {
  325.         return n;
  326.     }
  327.     return n - 1;
  328.     }
  329.  
  330.     /**
  331.      * Determines the offset of the start of the given line.
  332.      *
  333.      * @param line  the line number to translate >= 0
  334.      * @return the offset >= 0
  335.      * @exception BadLocationException thrown if the line is
  336.      * less than zero or greater or equal to the number of
  337.      * lines contained in the document (as reported by 
  338.      * getLineCount).
  339.      */
  340.     public int getLineStartOffset(int line) throws BadLocationException {
  341.         Element map = getDocument().getDefaultRootElement();
  342.         if (line < 0) {
  343.             throw new BadLocationException("Negative line", -1);
  344.         } else if (line >= map.getElementCount()) {
  345.             throw new BadLocationException("No such line", getDocument().getLength()+1);
  346.         } else {
  347.             Element lineElem = map.getElement(line);
  348.             return lineElem.getStartOffset();
  349.         }
  350.     }
  351.  
  352.     /**
  353.      * Determines the offset of the end of the given line.
  354.      *
  355.      * @param line  the line >= 0
  356.      * @return the offset >= 0
  357.      * @exception BadLocationException Thrown if the line is
  358.      * less than zero or greater or equal to the number of
  359.      * lines contained in the document (as reported by 
  360.      * getLineCount).
  361.      */
  362.     public int getLineEndOffset(int line) throws BadLocationException {
  363.         Element map = getDocument().getDefaultRootElement();
  364.         if (line < 0) {
  365.             throw new BadLocationException("Negative line", -1);
  366.         } else if (line >= map.getElementCount()) {
  367.             throw new BadLocationException("No such line", getDocument().getLength()+1);
  368.         } else {
  369.             Element lineElem = map.getElement(line);
  370.             return lineElem.getEndOffset();
  371.         }
  372.     }
  373.  
  374.     // --- java.awt.TextArea methods ---------------------------------
  375.  
  376.     /**
  377.      * Inserts the specified text at the specified position.  Does nothing
  378.      * if the model is null or if the text is null or empty.
  379.      * <p>
  380.      * This method is thread safe, although most Swing methods
  381.      * are not. Please see 
  382.      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  383.      * and Swing</A> for more information.     
  384.      *
  385.      * @param str the text to insert
  386.      * @param pos the position at which to insert >= 0
  387.      * @exception IllegalArgumentException  if pos is an
  388.      *  invalid position in the model
  389.      * @see TextComponent#setText
  390.      * @see #replaceRange
  391.      */
  392.     public void insert(String str, int pos) {
  393.         Document doc = getDocument();
  394.         if (doc != null) {
  395.             try {
  396.                 doc.insertString(pos, str, null);
  397.             } catch (BadLocationException e) {
  398.                 throw new IllegalArgumentException(e.getMessage());
  399.             }
  400.         }
  401.     }
  402.  
  403.     /**
  404.      * Appends the given text to the end of the document.  Does nothing if
  405.      * the model is null or the string is null or empty.
  406.      * <p>
  407.      * This method is thread safe, although most Swing methods
  408.      * are not. Please see 
  409.      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  410.      * and Swing</A> for more information.     
  411.      *
  412.      * @param str the text to insert
  413.      * @see #insert
  414.      */
  415.     public void append(String str) {
  416.         Document doc = getDocument();
  417.         if (doc != null) {
  418.             try {
  419.                 doc.insertString(doc.getLength(), str, null);
  420.             } catch (BadLocationException e) {
  421.             }
  422.         }
  423.     }
  424.  
  425.     /**
  426.      * Replaces text from the indicated start to end position with the
  427.      * new text specified.  Does nothing if the model is null.  Simply
  428.      * does a delete if the new string is null or empty.
  429.      * <p>
  430.      * This method is thread safe, although most Swing methods
  431.      * are not. Please see 
  432.      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  433.      * and Swing</A> for more information.     
  434.      *
  435.      * @param str the text to use as the replacement
  436.      * @param start the start position >= 0
  437.      * @param end the end position >= start
  438.      * @exception IllegalArgumentException  if part of the range is an
  439.      *  invalid position in the model
  440.      * @see #insert
  441.      * @see #replaceRange
  442.      */
  443.     public void replaceRange(String str, int start, int end) {
  444.         if (end < start) {
  445.             throw new IllegalArgumentException("end before start");
  446.         }
  447.         Document doc = getDocument();
  448.         if (doc != null) {
  449.             try {
  450.                 doc.remove(start, end - start);
  451.                 doc.insertString(start, str, null);
  452.             } catch (BadLocationException e) {
  453.                 throw new IllegalArgumentException(e.getMessage());
  454.             }
  455.         }
  456.     }
  457.  
  458.     /**
  459.      * Turns off tab traversal once focus gained.
  460.      *
  461.      * @return true, to indicate that the focus is being managed
  462.      */
  463.     public boolean isManagingFocus() {
  464.         return true;
  465.     }
  466.  
  467.     /**
  468.      * Make sure that TAB and Shift-TAB events get consumed, so that
  469.      * awt doesn't attempt focus traversal.
  470.      *
  471.      */
  472.  
  473.     protected void processComponentKeyEvent(KeyEvent e)  {
  474.         super.processComponentKeyEvent(e);
  475.         // tab consumption
  476.     // We are actually consuming any TABs modified in any way, because
  477.     // we don't want awt to get anything it can use for focus traversal.
  478.     if (isManagingFocus()) {
  479.       if ((e.getKeyCode() == KeyEvent.VK_TAB || e.getKeyChar() == '\t')) {
  480.         e.consume();
  481.       }
  482.     }
  483.     }
  484.  
  485.     /**
  486.      * Returns the number of rows in the TextArea.
  487.      *
  488.      * @return the number of rows >= 0
  489.      */
  490.     public int getRows() {
  491.         return rows;
  492.     }
  493.  
  494.     /**
  495.      * Sets the number of rows for this TextArea.  Calls invalidate() after
  496.      * setting the new value.
  497.      *
  498.      * @param rows the number of rows >= 0
  499.      * @exception IllegalArgumentException if rows is less than 0
  500.      * @see #getRows
  501.      * @beaninfo
  502.      * description: the number of rows preferred for display
  503.      */
  504.     public void setRows(int rows) {
  505.         int oldVal = this.rows;
  506.         if (rows < 0) {
  507.             throw new IllegalArgumentException("rows less than zero.");
  508.         }
  509.         if (rows != oldVal) {
  510.             this.rows = rows;
  511.             invalidate();
  512.         }
  513.     }
  514.  
  515.     /**
  516.      * Defines the meaning of the height of a row.  This defaults to
  517.      * the height of the font.
  518.      *
  519.      * @return the height >= 1
  520.      */
  521.     protected int getRowHeight() {
  522.         if (rowHeight == 0) {
  523.             FontMetrics metrics = getFontMetrics(getFont());
  524.             rowHeight = metrics.getHeight();
  525.         }
  526.         return rowHeight;
  527.     }
  528.  
  529.     /**
  530.      * Returns the number of columns in the TextArea.
  531.      *
  532.      * @return number of columns >= 0
  533.      */
  534.     public int getColumns() {
  535.         return columns;
  536.     }
  537.  
  538.     /**
  539.      * Sets the number of columns for this TextArea.  Does an invalidate()
  540.      * after setting the new value.
  541.      *
  542.      * @param columns the number of columns >= 0
  543.      * @exception IllegalArgumentException if columns is less than 0
  544.      * @see #getColumns
  545.      * @beaninfo
  546.      * description: the number of columns preferred for display
  547.      */
  548.     public void setColumns(int columns) {
  549.         int oldVal = this.columns;
  550.         if (columns < 0) {
  551.             throw new IllegalArgumentException("columns less than zero.");
  552.         }
  553.         if (columns != oldVal) {
  554.             this.columns = columns;
  555.             invalidate();
  556.         }
  557.     }
  558.  
  559.     /**
  560.      * Gets column width.
  561.      * The meaning of what a column is can be considered a fairly weak
  562.      * notion for some fonts.  This method is used to define the width
  563.      * of a column.  By default this is defined to be the width of the
  564.      * character <em>m</em> for the font used.  This method can be 
  565.      * redefined to be some alternative amount.
  566.      *
  567.      * @return the column width >= 1
  568.      */
  569.     protected int getColumnWidth() {
  570.         if (columnWidth == 0) {
  571.             FontMetrics metrics = getFontMetrics(getFont());
  572.             columnWidth = metrics.charWidth('m');
  573.         }
  574.         return columnWidth;
  575.     }
  576.  
  577.     // --- Component methods -----------------------------------------
  578.  
  579.     /**
  580.      * Returns the preferred size of the TextArea.  This is the
  581.      * maximum of the size needed to display the text and the
  582.      * size requested for the viewport.
  583.      *
  584.      * @return the size
  585.      */
  586.     public Dimension getPreferredSize() {
  587.     Dimension d = super.getPreferredSize();
  588.         d = (d == null) ? new Dimension(400,400) : d;
  589.         if (columns != 0) {
  590.         d.width = Math.max(d.width, columns * getColumnWidth());
  591.     }
  592.     if (rows != 0) {
  593.         d.height = Math.max(d.height, rows * getRowHeight());
  594.     }
  595.     return d;
  596.     }
  597.  
  598.     /**
  599.      * Sets the current font.  This removes cached row height and column
  600.      * width so the new font will be reflected, and calls revalidate().
  601.      *
  602.      * @param f the font to use as the current font
  603.      */
  604.     public void setFont(Font f) {
  605.         super.setFont(f);
  606.         rowHeight = 0; 
  607.         columnWidth = 0;
  608.     }
  609.  
  610.  
  611.     /**
  612.      * Returns a string representation of this JTextArea. This method 
  613.      * is intended to be used only for debugging purposes, and the 
  614.      * content and format of the returned string may vary between      
  615.      * implementations. The returned string may be empty but may not 
  616.      * be <code>null</code>.
  617.      * <P>
  618.      * Overriding paramString() to provide information about the
  619.      * specific new aspects of the JFC components.
  620.      * 
  621.      * @return  a string representation of this JTextArea.
  622.      */
  623.     protected String paramString() {
  624.         String wrapString = (wrap ?
  625.                  "true" : "false");
  626.         String wordString = (word ?
  627.                  "true" : "false");
  628.  
  629.         return super.paramString() +
  630.         ",colums=" + columns +
  631.         ",columWidth=" + columnWidth +
  632.         ",rows=" + rows +
  633.         ",rowHeight=" + rowHeight +
  634.         ",word=" + wordString +
  635.         ",wrap=" + wrapString;
  636.     }
  637.  
  638.     // --- Scrollable methods ----------------------------------------
  639.  
  640.     /**
  641.      * Returns true if a viewport should always force the width of this 
  642.      * Scrollable to match the width of the viewport.  This is implemented
  643.      * to return true if the line wrapping policy is true, and false
  644.      * if lines are not being wrapped.
  645.      * 
  646.      * @return true if a viewport should force the Scrollables width
  647.      * to match its own.
  648.      */
  649.     public boolean getScrollableTracksViewportWidth() {
  650.         return (wrap) ? true : super.getScrollableTracksViewportWidth();
  651.     }
  652.  
  653.     /**
  654.      * Returns the preferred size of the viewport if this component
  655.      * is embedded in a JScrollPane.  This uses the desired column
  656.      * and row settings if they have been set, otherwise the superclass
  657.      * behavior is used.
  658.      * 
  659.      * @return The preferredSize of a JViewport whose view is this Scrollable.
  660.      * @see JViewport#getPreferredSize
  661.      */
  662.     public Dimension getPreferredScrollableViewportSize() {
  663.         Dimension size = super.getPreferredScrollableViewportSize();
  664.         size = (size == null) ? new Dimension(400,400) : size;
  665.         size.width = (columns == 0) ? size.width : columns * getColumnWidth();
  666.         size.height = (rows == 0) ? size.height : rows * getRowHeight();
  667.         return size;
  668.     }
  669.  
  670.     /**
  671.      * Components that display logical rows or columns should compute
  672.      * the scroll increment that will completely expose one new row
  673.      * or column, depending on the value of orientation.  This is implemented
  674.      * to use the vaules returned by the <code>getRowHeight</code> and
  675.      * <code>getColumnWidth</code> methods.
  676.      * <p>
  677.      * Scrolling containers, like JScrollPane, will use this method
  678.      * each time the user requests a unit scroll.
  679.      * 
  680.      * @param visibleRect the view area visible within the viewport
  681.      * @param orientation Either SwingConstants.VERTICAL or
  682.      *   SwingConstants.HORIZONTAL.
  683.      * @param direction Less than zero to scroll up/left,
  684.      *   greater than zero for down/right.
  685.      * @return The "unit" increment for scrolling in the specified direction
  686.      * @exception IllegalArgumentException for an invalid orientation
  687.      * @see JScrollBar#setUnitIncrement
  688.      * @see #getRowHeight
  689.      * @see #getColumnWidth
  690.      */
  691.     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
  692.         switch (orientation) {
  693.         case SwingConstants.VERTICAL:
  694.             return getRowHeight();
  695.         case SwingConstants.HORIZONTAL:
  696.             return getColumnWidth();
  697.         default:
  698.             throw new IllegalArgumentException("Invalid orientation: " + orientation);
  699.         }
  700.     }
  701.  
  702.     /** 
  703.      * See readObject() and writeObject() in JComponent for more 
  704.      * information about serialization in Swing.
  705.      */
  706.     private void writeObject(ObjectOutputStream s) throws IOException {
  707.         s.defaultWriteObject();
  708.     if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  709.         ui.installUI(this);
  710.     }
  711.     }
  712.  
  713. /////////////////
  714. // Accessibility support
  715. ////////////////
  716.  
  717.  
  718.     /**
  719.      * Get the AccessibleContext associated with this JTextArea.
  720.      * Creates a new context if necessary.
  721.      *
  722.      * @return the AccessibleContext of this JTextArea
  723.      */
  724.     public AccessibleContext getAccessibleContext() {
  725.         if (accessibleContext == null) {
  726.             accessibleContext = new AccessibleJTextArea();
  727.         }
  728.         return accessibleContext;
  729.     }
  730.  
  731.     /**
  732.      * The class used to obtain the accessible role for this object.
  733.      * <p>
  734.      * <strong>Warning:</strong>
  735.      * Serialized objects of this class will not be compatible with
  736.      * future Swing releases.  The current serialization support is appropriate
  737.      * for short term storage or RMI between applications running the same
  738.      * version of Swing.  A future release of Swing will provide support for
  739.      * long term persistence.
  740.      */
  741.     protected class AccessibleJTextArea extends AccessibleJTextComponent {
  742.  
  743.         /**
  744.          * Gets the state set of this object.
  745.          *
  746.          * @return an instance of AccessibleStateSet describing the states
  747.          * of the object
  748.          * @see AccessibleStateSet
  749.          */
  750.         public AccessibleStateSet getAccessibleStateSet() {
  751.             AccessibleStateSet states = super.getAccessibleStateSet();
  752.             states.add(AccessibleState.MULTI_LINE);
  753.             return states;
  754.         }
  755.     }
  756.  
  757.     // --- variables -------------------------------------------------
  758.  
  759.     private int rows;
  760.     private int columns;
  761.     private int columnWidth;
  762.     private int rowHeight;
  763.     private boolean wrap;
  764.     private boolean word;
  765.  
  766. }
  767.